﻿using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using GMap.NET;
using Schedulr.Models;

namespace Schedulr.Views.Controls
{
    /// <summary>
    /// Interaction logic for GeoLocationMap.xaml
    /// </summary>
    public partial class GeoLocationMap : UserControl
    {
        #region Constructors

        public GeoLocationMap()
        {
            InitializeComponent();

            this.geoGMapControl.Manager.Mode = AccessMode.ServerOnly;
            this.geoGMapControl.MapType = MapType.BingMap;
            this.geoGMapControl.DragButton = MouseButton.Left;
            this.geoGMapControl.MouseWheelZoomType = MouseWheelZoomType.MousePositionWithoutCenter;
            this.geoGMapControl.MinZoom = 1;
            this.geoGMapControl.MaxZoom = 16;
            this.geoGMapControl.Zoom = 1;
            this.geoGMapControl.OnMapZoomChanged += new MapZoomChanged(geoGMapControl_OnMapZoomChanged);
            this.geoGMapControl.OnCurrentPositionChanged += new CurrentPositionChanged(geoGMapControl_OnCurrentPositionChanged);
            this.geoGMapControl.Manager.UseGeocoderCache = false;
        }

        #endregion

        #region Event Handlers

        private void geoGMapControl_OnCurrentPositionChanged(PointLatLng point)
        {
            this.Location.Latitude = point.Lat;
            this.Location.Longitude = point.Lng;
        }

        private void geoGMapControl_OnMapZoomChanged()
        {
            this.Location.Accuracy = (int)this.geoGMapControl.Zoom;
        }

        #endregion

        #region IsReadOnly

        public bool IsReadOnly
        {
            get { return (bool)GetValue(IsReadOnlyProperty); }
            set { SetValue(IsReadOnlyProperty, value); }
        }

        public static readonly DependencyProperty IsReadOnlyProperty = DependencyProperty.Register("IsReadOnly", typeof(bool), typeof(GeoLocationMap), new UIPropertyMetadata(false, OnIsReadOnlyChanged));

        private static void OnIsReadOnlyChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
        {
            var instance = (GeoLocationMap)o;
            instance.geoGMapControl.IsEnabled = !instance.IsReadOnly;
            instance.zoomStackPanel.Visibility = (instance.IsReadOnly ? Visibility.Collapsed : Visibility.Visible);
        }

        #endregion

        #region Location

        public GeoLocation Location
        {
            get { return (GeoLocation)GetValue(LocationProperty); }
            set { SetValue(LocationProperty, value); }
        }

        public static readonly DependencyProperty LocationProperty = DependencyProperty.Register("Location", typeof(GeoLocation), typeof(GeoLocationMap), new UIPropertyMetadata(new GeoLocation(), OnLocationChanged));

        private static void OnLocationChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            var instance = (GeoLocationMap)sender;

            var oldLocation = e.OldValue as GeoLocation;
            if (oldLocation != null)
            {
                oldLocation.PropertyChanged -= instance.Location_PropertyChanged;
            }

            if (instance.Location == null)
            {
                instance.Location = new GeoLocation();
            }
            instance.Location.PropertyChanged += instance.Location_PropertyChanged;
            instance.UpdateMap();
        }

        private void Location_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            UpdateMap();
        }

        private void UpdateMap()
        {
            this.geoGMapControl.Position = new PointLatLng(this.Location.Latitude, this.Location.Longitude);
            this.geoGMapControl.Zoom = Math.Max(1, (double)this.Location.Accuracy);
        }

        #endregion

        #region SearchLocation

        /// <summary>
        /// Searches for a location and sets the current position if found.
        /// </summary>
        /// <param name="searchText">The location to search for.</param>
        /// <returns><see langword="true"/> if the location was found, <see langword="false"/> otherwise.</returns>
        public bool SearchLocation(string searchText)
        {
            var status = this.geoGMapControl.SetCurrentPositionByKeywords(searchText);
            return (status == GeoCoderStatusCode.G_GEO_SUCCESS);
        }

        #endregion
    }
}